`include "lib/defines.vh"
module EX(
    input wire clk,
    input wire rst,
    // input wire flush,
    input wire [`StallBus-1:0] stall,

    input wire [`ID_TO_EX_WD-1:0] id_to_ex_bus,     // 从译码阶段传来的数据总线，159位

    output wire [`EX_TO_MEM_WD-1:0] ex_to_mem_bus,  // 传递给存储器阶段的数据总线，76位

    output wire data_sram_en,
    output wire [3:0] data_sram_wen,
    output wire [31:0] data_sram_addr,
    output wire [37:0] ex_to_id,
    output wire [31:0] data_sram_wdata,

    output wire stallreq_from_ex,
    output wire ex_is_load,
    output wire [65:0] hilo_ex_to_id
);

    reg [`ID_TO_EX_WD-1:0] id_to_ex_bus_r;

    always @ (posedge clk) begin
        if (rst) begin
            id_to_ex_bus_r <= `ID_TO_EX_WD'b0;
        end
        // else if (flush) begin
        //     id_to_ex_bus_r <= `ID_TO_EX_WD'b0;
        // end
        else if (stall[2]==`Stop && stall[3]==`NoStop) begin
            id_to_ex_bus_r <= `ID_TO_EX_WD'b0;
        end
        else if (stall[2]==`NoStop) begin
            id_to_ex_bus_r <= id_to_ex_bus;
        end
    end

    wire [31:0] ex_pc, inst;
    wire [11:0] alu_op;
    wire [2:0] sel_alu_src1;
    wire [3:0] sel_alu_src2;
    wire data_ram_en;
    wire [3:0] data_ram_wen;
    wire [3:0] data_ram_readen;
    wire rf_we;
    wire [4:0] rf_waddr;
    wire sel_rf_res;
    wire [31:0] rf_rdata1;
    wire [31:0] rf_rdata2;
    reg is_in_delayslot;

    assign {
        
        inst_mthi,      //168
        inst_mtlo,      //167
        inst_multu,     //166
        inst_mult,      //165
        inst_divu,      //164
        inst_div,       //163
        ex_pc,          //162:131
        inst,           //130:99
        alu_op,         //98:87
        sel_alu_src1,   //86:84
        sel_alu_src2,   //83:80
        data_ram_en,    // 79
        data_ram_wen,   // 78:75
        data_ram_readen,//74: 71
        rf_we,          // 70            // write
        rf_waddr,       // 69:65         //write
        sel_rf_res,     // 64
        rf_rdata1,      // 63:32      //rs
        rf_rdata2       // 31:0      //rt
    } = id_to_ex_bus_r;

    assign ex_is_load = (inst[31:26] == 6'b10_0011) ? 1'b1 : 1'b0; //判断当前指令是否为加载指令

    wire [31:0] imm_sign_extend, imm_zero_extend, sa_zero_extend;
    assign imm_sign_extend = {{16{inst[15]}},inst[15:0]};
    assign imm_zero_extend = {16'b0, inst[15:0]};
    assign sa_zero_extend = {27'b0,inst[10:6]};

    wire [31:0] alu_src1, alu_src2;
    wire [31:0] alu_result, ex_result;

    assign alu_src1 = sel_alu_src1[1] ? ex_pc :
                      sel_alu_src1[2] ? sa_zero_extend : rf_rdata1;

    assign alu_src2 = sel_alu_src2[1] ? imm_sign_extend :
                      sel_alu_src2[2] ? 32'd8 :
                      sel_alu_src2[3] ? imm_zero_extend : rf_rdata2;
    
    alu u_alu(
    	.alu_control (alu_op        ),
        .alu_src1    (alu_src1      ),
        .alu_src2    (alu_src2      ),
        .alu_result  (alu_result    )
    );

    assign ex_result = alu_result;

    // 前六个信号直接由id_to_ex_bus总线通过id_to_ex_bus_r传入
    // 最后一个信号ex_result由alu计算得到
    assign ex_to_mem_bus = { 
        
        ex_pc,          //79:48
        data_ram_en,    //47
        data_ram_wen,   //46:43
        data_ram_readen,//42:39
        sel_rf_res,     // 38
        rf_we,          // 37
        rf_waddr,       // 36:32
        ex_result       // 31:0
    };

    assign  ex_to_id ={   
        rf_we,          // 37
        rf_waddr,       // 36:32
        ex_result       // 31:0
    };

    assign data_sram_en = data_ram_en;
    // 写使能信号判断
    assign data_sram_wen =   (data_ram_readen==4'b0101 && ex_result[1:0] == 2'b00 )? 4'b0001 
                            :(data_ram_readen==4'b0101 && ex_result[1:0] == 2'b01 )? 4'b0010
                            :(data_ram_readen==4'b0101 && ex_result[1:0] == 2'b10 )? 4'b0100
                            :(data_ram_readen==4'b0101 && ex_result[1:0] == 2'b11 )? 4'b1000
                            :(data_ram_readen==4'b0111 && ex_result[1:0] == 2'b00 )? 4'b0011
                            :(data_ram_readen==4'b0111 && ex_result[1:0]== 2'b10 )? 4'b1100
                            : data_ram_wen;
    
    assign data_sram_addr = ex_result;

    //写入内存的数据
    assign data_sram_wdata = data_sram_wen==4'b1111 ? rf_rdata2 
                            :data_sram_wen==4'b0001 ? {24'b0,rf_rdata2[7:0]}
                            :data_sram_wen==4'b0010 ? {16'b0,rf_rdata2[7:0],8'b0}
                            :data_sram_wen==4'b0100 ? {8'b0,rf_rdata2[7:0],16'b0}
                            :data_sram_wen==4'b1000 ? {rf_rdata2[7:0],24'b0}
                            :data_sram_wen==4'b0011 ? {16'b0,rf_rdata2[15:0]}
                            :data_sram_wen==4'b1100 ? {rf_rdata2[15:0],16'b0}
                            :32'b0;

    // IF data_sram_wen == 4'b1111 THEN
    //     data_sram_wdata = rf_rdata2
    // ELSE IF data_sram_wen == 4'b0001 THEN
    //     data_sram_wdata = {24'b0, rf_rdata2[7:0]}
    // ELSE IF data_sram_wen == 4'b0010 THEN
    //     data_sram_wdata = {16'b0, rf_rdata2[7:0], 8'b0}
    // ELSE IF data_sram_wen == 4'b0100 THEN
    //     data_sram_wdata = {8'b0, rf_rdata2[7:0], 16'b0}
    // ELSE IF data_sram_wen == 4'b1000 THEN
    //     data_sram_wdata = {rf_rdata2[7:0], 24'b0}
    // ELSE IF data_sram_wen == 4'b0011 THEN
    //     data_sram_wdata = {16'b0, rf_rdata2[15:0]}
    // ELSE IF data_sram_wen == 4'b1100 THEN
    //     data_sram_wdata = {rf_rdata2[15:0], 16'b0}
    // ELSE
    //     data_sram_wdata = 32'b0
    // END IF



    wire inst_mthi,inst_mtlo;
    wire hi_wen, lo_wen;        // HI/LO寄存器写使能信号
    wire [31:0] hi_data,lo_data;// HI/LO寄存器写入数据  

    // HI寄存器写使能条件:
    assign hi_wen = inst_divu | inst_div | inst_mult | inst_multu | inst_mthi;
    // 当执行除法(div/divu)、乘法(mult/multu)或mthi指令时置1

    // LO寄存器写使能条件:
    assign lo_wen = inst_divu | inst_div | inst_mult | inst_multu | inst_mtlo;
    // 当执行除法(div/divu)、乘法(mult/multu)或mtlo指令时置1

    // HI寄存器数据来源:
    assign hi_data = 
        (inst_div|inst_divu)   ? div_result[63:32] // 除法余数
        : (inst_mult|inst_multu) ? mul_result[63:32] // 乘法高32位
        : (inst_mthi)            ? rf_rdata1         // mthi指令直接写入
        : (32'b0);

    // LO寄存器数据来源:
    assign lo_data = 
        (inst_div|inst_divu)   ? div_result[31:0]  // 除法商
        : (inst_mult|inst_multu) ? mul_result[31:0]  // 乘法低32位
        : (inst_mtlo)            ? rf_rdata1         // mtlo指令直接写入
        : (32'b0);



    // 将HI/LO相关信息打包传递到ID阶段
    assign hilo_ex_to_id = {
        hi_wen,    // 写使能信号
        lo_wen,    // 写使能信号
        hi_data,   // HI数据
        lo_data    // LO数据
    };



    // MUL part
    wire [63:0] mul_result;


    // wire mul_signed; // 有符号乘法标记

    // mul u_mul(
    // 	.clk        (clk            ),
    //     .resetn     (~rst           ),
    //     .mul_signed (mul_signed     ),
    //     .ina        (      ), // 乘法源操作数1
    //     .inb        (      ), // 乘法源操作数2
    //     .result     (mul_result     ) // 乘法结果 64bit
    // );

    // 32位移位乘法器模块
    // 支持有符号(mult)和无符号(multu)乘法运算
    // 采用32周期移位实现，具有流水线停顿控制
    //******************************************************************

    // 控制与状态信号
    reg stallreq_for_mul;       // 乘法器停顿请求信号
    wire mul_ready_i;           // 乘法器就绪状态
    reg signed_mul_o;          // 乘法类型选择(1:有符号, 0:无符号)
    reg [31:0] mul_opdata1_o;  // 乘数1
    reg [31:0] mul_opdata2_o;  // 乘数2
    reg mul_start_o;           // 乘法开始控制信号

    // 实例化乘法器核心模块
    newmul new_mul(
        .rst            (rst                ),  // 复位信号
        .clk            (clk                ),  // 时钟信号
        .signed_mul_i   (signed_mul_o       ),  // 乘法类型输入
        .a_o            (mul_opdata1_o      ),  // 乘数1输入
        .b_o            (mul_opdata2_o      ),  // 乘数2输入
        .start_i        (mul_start_o        ),  // 启动信号
        .result_o       (mul_result         ),  // 乘法结果
        .ready_o        (mul_ready_i        )   // 就绪状态输出
    );

    // 乘法器控制组合逻辑
    always @ (*) begin
        // 复位状态：初始化所有控制信号
        if (rst) begin
            stallreq_for_mul = `NoStop;        // 不请求流水线停顿
            mul_opdata1_o = `ZeroWord;         // 清零操作数1
            mul_opdata2_o = `ZeroWord;         // 清零操作数2
            mul_start_o = `MulStop;            // 停止乘法运算
            signed_mul_o = 1'b0;               // 默认为无符号乘法
        end
        else begin
            // 默认状态：所有信号置为默认值
            stallreq_for_mul = `NoStop;        // 默认不停顿
            mul_opdata1_o = `ZeroWord;         // 默认操作数为0
            mul_opdata2_o = `ZeroWord;         
            mul_start_o = `MulStop;            // 默认不启动乘法
            signed_mul_o = 1'b0;               // 默认无符号
            
            case ({inst_mult,inst_multu})
                2'b10:begin                    // 有符号乘法指令(mult)处理
                    if (mul_ready_i == `MulResultNotReady) begin
                        mul_opdata1_o = rf_rdata1;        // 载入第一个操作数
                        mul_opdata2_o = rf_rdata2;        // 载入第二个操作数
                        mul_start_o = `MulStart;          // 启动乘法运算
                        signed_mul_o = 1'b1;              // 设置为有符号乘法
                        stallreq_for_mul = `Stop;         // 请求流水线停顿
                    end
                    else if (mul_ready_i == `MulResultReady) begin
                        mul_opdata1_o = rf_rdata1;        // 保持操作数
                        mul_opdata2_o = rf_rdata2;        // 保持操作数
                        mul_start_o = `MulStop;           // 停止乘法运算
                        signed_mul_o = 1'b1;              // 保持有符号状态
                        stallreq_for_mul = `NoStop;       // 撤销停顿请求
                    end
                    else begin                           // 其他异常状态
                        mul_opdata1_o = `ZeroWord;        // 重置所有信号
                        mul_opdata2_o = `ZeroWord;
                        mul_start_o = `MulStop;
                        signed_mul_o = 1'b0;
                        stallreq_for_mul = `NoStop;
                    end
                end
                2'b01:begin  // 无符号乘法指令(multu)的处理
                    if (mul_ready_i == `MulResultNotReady) begin
                        mul_opdata1_o = rf_rdata1;         // 设置第一个操作数
                        mul_opdata2_o = rf_rdata2;         // 设置第二个操作数
                        mul_start_o = `MulStart;           // 启动乘法运算
                        signed_mul_o = 1'b0;               // 设置为无符号乘法
                        stallreq_for_mul = `Stop;          // 请求流水线停顿
                    end
                    else if (mul_ready_i == `MulResultReady) begin
                        mul_opdata1_o = rf_rdata1;         // 保持操作数
                        mul_opdata2_o = rf_rdata2;         // 保持操作数
                        mul_start_o = `MulStop;            // 停止乘法运算
                        signed_mul_o = 1'b0;               // 保持无符号状态
                        stallreq_for_mul = `NoStop;        // 撤销停顿请求
                    end
                    else begin                            // 其他状态
                        mul_opdata1_o = `ZeroWord;         // 重置操作数
                        mul_opdata2_o = `ZeroWord;         // 重置操作数
                        mul_start_o = `MulStop;            // 停止乘法
                        signed_mul_o = 1'b0;               // 重置乘法类型
                        stallreq_for_mul = `NoStop;        // 无需停顿
                    end
                end
                default:begin
                end
            endcase
        end
    end

    // DIV part
    wire [63:0] div_result;
    wire div_ready_i;
    reg stallreq_for_div;
    assign stallreq_from_ex = stallreq_for_div | stallreq_for_mul;

    reg [31:0] div_opdata1_o; //被除数
    reg [31:0] div_opdata2_o; //除数
    reg div_start_o;
    reg signed_div_o; //是否是有符号除法

    div u_div(
    	.rst          (rst              ),  //复位
        .clk          (clk              ),  //时钟
        .signed_div_i (signed_div_o     ),  //是否为有符号除法运算，1位有符号
        .opdata1_i    (div_opdata1_o    ),  //被除数
        .opdata2_i    (div_opdata2_o    ),  //除数
        .start_i      (div_start_o      ),  //是否开始除法运算
        .annul_i      (1'b0             ),  //是否取消除法运算，1位取消
        .result_o     (div_result       ),  // 除法结果 64bit
        .ready_o      (div_ready_i      )   // 除法是否结束
    );

// 除法控制模块：控制有符号除法(div)和无符号除法(divu)的执行
always @ (*) begin
        if (rst) begin
            // 复位状态：初始化所有控制信号
            stallreq_for_div = `NoStop;          // 撤销暂停请求
            div_opdata1_o = `ZeroWord;          // 清零被除数
            div_opdata2_o = `ZeroWord;          // 清零除数
            div_start_o = `DivStop;             // 停止除法运算
            signed_div_o = 1'b0;                // 清除有符号除法标志
        end
        else begin
            // 非复位状态：默认值设置
            stallreq_for_div = `NoStop;
            div_opdata1_o = `ZeroWord;
            div_opdata2_o = `ZeroWord;
            div_start_o = `DivStop;
            signed_div_o = 1'b0;
            
            case ({inst_div,inst_divu})
                2'b10:begin                      // 有符号除法指令
                    if (div_ready_i == `DivResultNotReady) begin
                        // 除法结果未就绪：启动除法运算并暂停流水线
                        div_opdata1_o = rf_rdata1;       // 设置被除数
                        div_opdata2_o = rf_rdata2;       // 设置除数
                        div_start_o = `DivStart;         // 启动除法运算
                        signed_div_o = 1'b1;             // 设置为有符号除法
                        stallreq_for_div = `Stop;        // 请求暂停流水线
                    end
                    else if (div_ready_i == `DivResultReady) begin
                        // 除法结果就绪：保持操作数但停止除法运算
                        div_opdata1_o = rf_rdata1;       // 保持被除数
                        div_opdata2_o = rf_rdata2;       // 保持除数
                        div_start_o = `DivStop;          // 停止除法运算
                        signed_div_o = 1'b1;             // 保持有符号除法标志
                        stallreq_for_div = `NoStop;      // 撤销暂停请求
                    end
                    else begin
                        // 其他状态：恢复默认值
                        div_opdata1_o = `ZeroWord;
                        div_opdata2_o = `ZeroWord;
                        div_start_o = `DivStop;
                        signed_div_o = 1'b0;
                        stallreq_for_div = `NoStop;
                    end
                end
                2'b01:begin                      // 无符号除法指令
                    if (div_ready_i == `DivResultNotReady) begin
                        // 除法结果未就绪：启动除法运算并暂停流水线
                        div_opdata1_o = rf_rdata1;       // 设置被除数
                        div_opdata2_o = rf_rdata2;       // 设置除数
                        div_start_o = `DivStart;         // 启动除法运算
                        signed_div_o = 1'b0;             // 设置为无符号除法
                        stallreq_for_div = `Stop;        // 请求暂停流水线
                    end
                    else if (div_ready_i == `DivResultReady) begin
                        // 除法结果就绪：保持操作数但停止除法运算
                        div_opdata1_o = rf_rdata1;       // 保持被除数
                        div_opdata2_o = rf_rdata2;       // 保持除数
                        div_start_o = `DivStop;          // 停止除法运算
                        signed_div_o = 1'b0;             // 保持无符号除法标志
                        stallreq_for_div = `NoStop;      // 撤销暂停请求
                    end
                    else begin
                        // 其他状态：恢复默认值
                        div_opdata1_o = `ZeroWord;
                        div_opdata2_o = `ZeroWord;
                        div_start_o = `DivStop;
                        signed_div_o = 1'b0;
                        stallreq_for_div = `NoStop;
                    end
                end
                default:begin                    // 非除法指令：保持默认值
                end
            endcase
        end
    end

    // mul_result 和 div_result 可以直接使用
    
    
endmodule